#ifndef THINK_THINK_MODEL_MERGE_H
#define THINK_THINK_MODEL_MERGE_H

static char* think_model_merge =
	"\n"
	"// +----------------------------------------------------------------------\n"
	"// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n"
	"// +----------------------------------------------------------------------\n"
	"// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.\n"
	"// +----------------------------------------------------------------------\n"
	"// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n"
	"// +----------------------------------------------------------------------\n"
	"// | Author: liu21st <liu21st@gmail.com>\n"
	"// +----------------------------------------------------------------------\n"
	"\n"
	"namespace think\\model;\n"
	"\n"
	"use think\\Db;\n"
	"use think\\db\\Query;\n"
	"use think\\Model;\n"
	"\n"
	"class Merge extends Model\n"
	"{\n"
	"\n"
	"    protected $relationModel = []; // HAS ONE 关联的模型列表\n"
	"    protected $fk            = \'\'; //  外键名 默认为主表名_id\n"
	"    protected $mapFields     = []; //  需要处理的模型映射字段，避免混淆 array( id => \'user.id\'  )\n"
	"\n"
	"    /**\n"
	"     * 构造函数\n"
	"     * @access public\n"
	"     * @param array|object $data 数据\n"
	"     */\n"
	"    public function __construct($data = [])\n"
	"    {\n"
	"        parent::__construct($data);\n"
	"\n"
	"        // 设置默认外键名 仅支持单一外键\n"
	"        if (empty($this->fk)) {\n"
	"            $this->fk = strtolower($this->name) . \'_id\';\n"
	"        }\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 查找单条记录\n"
	"     * @access public\n"
	"     * @param mixed        $data  主键值或者查询条件（闭包）\n"
	"     * @param string|array $with  关联预查询\n"
	"     * @param bool         $cache 是否缓存\n"
	"     * @return \\think\\Model\n"
	"     */\n"
	"    public static function get($data = null, $with = [], $cache = false)\n"
	"    {\n"
	"        $query = self::parseQuery($data, $with, $cache);\n"
	"        $query = self::attachQuery($query);\n"
	"        return $query->find($data);\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 附加查询表达式\n"
	"     * @access protected\n"
	"     * @param \\think\\db\\Query $query 查询对象\n"
	"     * @return \\think\\db\\Query\n"
	"     */\n"
	"    protected static function attachQuery($query)\n"
	"    {\n"
	"        $class  = new static();\n"
	"        $master = $class->name;\n"
	"        $fields = self::getModelField($query, $master, \'\', $class->mapFields, $class->field);\n"
	"        $query->alias($master)->field($fields);\n"
	"\n"
	"        foreach ($class->relationModel as $key => $model) {\n"
	"            $name  = is_int($key) ? $model : $key;\n"
	"            $table = is_int($key) ? $query->getTable($name) : $model;\n"
	"            $query->join($table . \' \' . $name, $name . \'.\' . $class->fk . \'=\' . $master . \'.\' . $class->getPk());\n"
	"            $fields = self::getModelField($query, $name, $table, $class->mapFields, $class->field);\n"
	"            $query->field($fields);\n"
	"        }\n"
	"        return $query;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 获取关联模型的字段 并解决混淆\n"
	"     * @access protected\n"
	"     * @param \\think\\db\\Query $query  查询对象\n"
	"     * @param string          $name   模型名称\n"
	"     * @param string          $table  关联表名称\n"
	"     * @param array           $map    字段映射\n"
	"     * @param array           $fields 查询字段\n"
	"     * @return array\n"
	"     */\n"
	"    protected static function getModelField($query, $name, $table = \'\', $map = [], $fields = [])\n"
	"    {\n"
	"        // 获取模型的字段信息\n"
	"        $fields = $fields ?: $query->getTableInfo($table, \'fields\');\n"
	"        $array  = [];\n"
	"        foreach ($fields as $field) {\n"
	"            if ($key = array_search($name . \'.\' . $field, $map)) {\n"
	"                // 需要处理映射字段\n"
	"                $array[] = $name . \'.\' . $field . \' AS \' . $key;\n"
	"            } else {\n"
	"                $array[] = $field;\n"
	"            }\n"
	"        }\n"
	"        return $array;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 查找所有记录\n"
	"     * @access public\n"
	"     * @param mixed        $data 主键列表或者查询条件（闭包）\n"
	"     * @param array|string $with 关联预查询\n"
	"     * @param bool         $cache\n"
	"     * @return array|false|string\n"
	"     */\n"
	"    public static function all($data = null, $with = [], $cache = false)\n"
	"    {\n"
	"        $query = self::parseQuery($data, $with, $cache);\n"
	"        $query = self::attachQuery($query);\n"
	"        return $query->select($data);\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 处理写入的模型数据\n"
	"     * @access public\n"
	"     * @param string $model  模型名称\n"
	"     * @param array  $data   数据\n"
	"     * @return array\n"
	"     */\n"
	"    protected function parseData($model, $data)\n"
	"    {\n"
	"        $item = [];\n"
	"        foreach ($data as $key => $val) {\n"
	"            if ($this->fk != $key && array_key_exists($key, $this->mapFields)) {\n"
	"                list($name, $key) = explode(\'.\', $this->mapFields[$key]);\n"
	"                if ($model == $name) {\n"
	"                    $item[$key] = $val;\n"
	"                }\n"
	"            } else {\n"
	"                $item[$key] = $val;\n"
	"            }\n"
	"        }\n"
	"        return $item;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 保存模型数据 以及关联数据\n"
	"     * @access public\n"
	"     * @param mixed  $data     数据\n"
	"     * @param array  $where    更新条件\n"
	"     * @param string $sequence 自增序列名\n"
	"     * @return false|int\n"
	"     * @throws \\Exception\n"
	"     */\n"
	"    public function save($data = [], $where = [], $sequence = null)\n"
	"    {\n"
	"        if (!empty($data)) {\n"
	"            // 数据自动验证\n"
	"            if (!$this->validateData($data)) {\n"
	"                return false;\n"
	"            }\n"
	"            // 数据对象赋值\n"
	"            foreach ($data as $key => $value) {\n"
	"                $this->setAttr($key, $value, $data);\n"
	"            }\n"
	"            if (!empty($where)) {\n"
	"                $this->isUpdate = true;\n"
	"            }\n"
	"        }\n"
	"\n"
	"        // 数据自动完成\n"
	"        $this->autoCompleteData($this->auto);\n"
	"\n"
	"        // 自动写入更新时间\n"
	"        if ($this->autoWriteTimestamp && $this->updateTime && !isset($this->data[$this->updateTime])) {\n"
	"            $this->setAttr($this->updateTime, null);\n"
	"        }\n"
	"\n"
	"        // 事件回调\n"
	"        if (false === $this->trigger(\'before_write\', $this)) {\n"
	"            return false;\n"
	"        }\n"
	"\n"
	"        $db = $this->db();\n"
	"        $db->startTrans();\n"
	"        $pk = $this->getPk();\n"
	"        try {\n"
	"            if ($this->isUpdate) {\n"
	"                // 自动写入\n"
	"                $this->autoCompleteData($this->update);\n"
	"\n"
	"                if (false === $this->trigger(\'before_update\', $this)) {\n"
	"                    return false;\n"
	"                }\n"
	"\n"
	"                if (empty($where) && !empty($this->updateWhere)) {\n"
	"                    $where = $this->updateWhere;\n"
	"                }\n"
	"\n"
	"                // 获取有更新的数据\n"
	"                $data = $this->getChangedData();\n"
	"                // 保留主键数据\n"
	"                foreach ($this->data as $key => $val) {\n"
	"                    if ($this->isPk($key)) {\n"
	"                        $data[$key] = $val;\n"
	"                    }\n"
	"                }\n"
	"                // 处理模型数据\n"
	"                $data = $this->parseData($this->name, $data);\n"
	"                if (is_string($pk) && isset($data[$pk])) {\n"
	"                    if (!isset($where[$pk])) {\n"
	"                        unset($where);\n"
	"                        $where[$pk] = $data[$pk];\n"
	"                    }\n"
	"                    unset($data[$pk]);\n"
	"                }\n"
	"                // 写入主表数据\n"
	"                $result = $db->strict(false)->where($where)->update($data);\n"
	"\n"
	"                // 写入附表数据\n"
	"                foreach ($this->relationModel as $key => $model) {\n"
	"                    $name  = is_int($key) ? $model : $key;\n"
	"                    $table = is_int($key) ? $db->getTable($model) : $model;\n"
	"                    // 处理关联模型数据\n"
	"                    $data = $this->parseData($name, $data);\n"
	"                    if (Db::table($table)->strict(false)->where($this->fk, $this->data[$this->getPk()])->update($data)) {\n"
	"                        $result = 1;\n"
	"                    }\n"
	"                }\n"
	"\n"
	"                // 新增回调\n"
	"                $this->trigger(\'after_update\', $this);\n"
	"            } else {\n"
	"                // 自动写入\n"
	"                $this->autoCompleteData($this->insert);\n"
	"\n"
	"                // 自动写入创建时间\n"
	"                if ($this->autoWriteTimestamp && $this->createTime && !isset($this->data[$this->createTime])) {\n"
	"                    $this->setAttr($this->createTime, null);\n"
	"                }\n"
	"\n"
	"                if (false === $this->trigger(\'before_insert\', $this)) {\n"
	"                    return false;\n"
	"                }\n"
	"\n"
	"                // 处理模型数据\n"
	"                $data = $this->parseData($this->name, $this->data);\n"
	"                // 写入主表数据\n"
	"                $result = $db->name($this->name)->strict(false)->insert($data);\n"
	"                if ($result) {\n"
	"                    $insertId = $db->getLastInsID($sequence);\n"
	"                    // 写入外键数据\n"
	"                    if ($insertId) {\n"
	"                        if (is_string($pk)) {\n"
	"                            $this->data[$pk] = $insertId;\n"
	"                        }\n"
	"                        $this->data[$this->fk] = $insertId;\n"
	"                    }\n"
	"\n"
	"                    // 写入附表数据\n"
	"                    $source = $this->data;\n"
	"                    if ($insertId && is_string($pk) && isset($source[$pk]) && $this->fk != $pk) {\n"
	"                        unset($source[$pk]);\n"
	"                    }\n"
	"                    foreach ($this->relationModel as $key => $model) {\n"
	"                        $name  = is_int($key) ? $model : $key;\n"
	"                        $table = is_int($key) ? $db->getTable($model) : $model;\n"
	"                        // 处理关联模型数据\n"
	"                        $data = $this->parseData($name, $source);\n"
	"                        Db::table($table)->strict(false)->insert($data);\n"
	"                    }\n"
	"                }\n"
	"                // 标记为更新\n"
	"                $this->isUpdate = true;\n"
	"                // 新增回调\n"
	"                $this->trigger(\'after_insert\', $this);\n"
	"            }\n"
	"            $db->commit();\n"
	"            // 写入回调\n"
	"            $this->trigger(\'after_write\', $this);\n"
	"\n"
	"            $this->origin = $this->data;\n"
	"            return $result;\n"
	"        } catch (\\Exception $e) {\n"
	"            $db->rollback();\n"
	"            throw $e;\n"
	"        }\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 删除当前的记录 并删除关联数据\n"
	"     * @access public\n"
	"     * @return int\n"
	"     * @throws \\Exception\n"
	"     */\n"
	"    public function delete()\n"
	"    {\n"
	"        if (false === $this->trigger(\'before_delete\', $this)) {\n"
	"            return false;\n"
	"        }\n"
	"\n"
	"        $db = $this->db();\n"
	"        $db->startTrans();\n"
	"        try {\n"
	"            $result = $db->delete($this->data);\n"
	"            if ($result) {\n"
	"                // 获取主键数据\n"
	"                $pk = $this->data[$this->getPk()];\n"
	"\n"
	"                // 删除关联数据\n"
	"                foreach ($this->relationModel as $key => $model) {\n"
	"                    $table = is_int($key) ? $db->getTable($model) : $model;\n"
	"                    $query = new Query;\n"
	"                    $query->table($table)->where($this->fk, $pk)->delete();\n"
	"                }\n"
	"            }\n"
	"            $this->trigger(\'after_delete\', $this);\n"
	"            $db->commit();\n"
	"            return $result;\n"
	"        } catch (\\Exception $e) {\n"
	"            $db->rollback();\n"
	"            throw $e;\n"
	"        }\n"
	"    }\n"
	"\n"
	"}\n"
	"\n"
;
#endif